package logic_food

import (
	"APT/internal/consts"
	"APT/internal/dao"
	"APT/internal/library/contexts"
	"APT/internal/library/hgorm/handler"
	hook2 "APT/internal/library/hgorm/hook"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_food"
	"APT/internal/model/input/input_refund"
	"APT/internal/service"
	"context"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
)

type sFoodOrder struct{}

func NewFoodOrder() *sFoodOrder {
	return &sFoodOrder{}
}

func init() {
	service.RegisterFoodOrder(NewFoodOrder())
}

func (s *sFoodOrder) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
	return handler.Model(dao.FoodOrder.Ctx(ctx), option...)
}

func (s *sFoodOrder) List(ctx context.Context, in *input_food.FoodOrderListInp) (list []*input_food.FoodOrderListModel, totalCount int, err error) {
	mod := s.Model(ctx).WithAll()

	mod = mod.Fields(input_food.FoodOrderListModel{})

	if !g.IsEmpty(in.OrderSn) {
		mod = mod.WhereLike(dao.FoodOrder.Columns().OrderSn, "%"+in.OrderSn+"%")
	}

	if !g.IsEmpty(in.RestaurantName) {

		uuIds, err := service.BasicsLanguage().GetUuids(ctx, in.RestaurantName, "name")
		if err == nil {
			restaurantIds, _ := service.FoodRestaurant().GetIds(ctx, uuIds)
			mod = mod.WhereIn(dao.FoodOrder.Columns().RestaurantId, restaurantIds)
		}
	}
	if !g.IsEmpty(in.OrderStatus) && in.OrderStatus != "ALL" {
		mod = mod.Where(dao.FoodOrder.Columns().OrderStatus, in.OrderStatus)
	}
	if !g.IsEmpty(in.BookingStatus) && in.BookingStatus != "ALL" {
		mod = mod.Where(dao.FoodOrder.Columns().BookingStatus, in.BookingStatus)
	}

	if !g.IsEmpty(in.GoodsName) {

		uuIds, err := service.BasicsLanguage().GetUuids(ctx, in.GoodsName, "goods_name")
		if err == nil {
			goodsIds, _ := service.FoodGoods().GetIds(ctx, uuIds)
			mod = mod.WhereIn(dao.FoodOrder.Columns().GoodsId, goodsIds)
		}
	}

	if len(in.CreatedAt) == 2 {
		mod = mod.WhereBetween(dao.FoodOrder.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
	}

	mod = mod.Page(in.Page, in.PerPage)

	mod = mod.OrderDesc(dao.FoodOrder.Columns().Id)
	mod = mod.Hook(hook2.PmsFindLanguageValueHook)

	if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
		err = gerror.Wrap(err, "获取预订单列表失败，请稍后重试！")
		return
	}
	return
}

func (s *sFoodOrder) View(ctx context.Context, in *input_food.FoodOrderViewInp) (res *input_food.FoodOrderViewModel, err error) {
	if err = s.Model(ctx).WithAll().Where(dao.FoodOrder.Columns().OrderSn, in.OrderSn).Hook(hook2.PmsFindLanguageValueHook).Scan(&res); err != nil {
		err = gerror.Wrap(err, "获取预订单信息，请稍后重试！")
		return
	}
	return
}

func (s *sFoodOrder) ConfirmAgree(ctx context.Context, in *input_food.FoodOrderConfirmAgreeInp) (err error) {

	var models *entity.FoodOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "HAVE_PAID" {
		err = gerror.New("订单支付状态不正确")
		return
	}

	if models.BookingStatus != "WAIT_CONFIRM" {
		err = gerror.New("订单确认状态不正确")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		if _, err = s.Model(ctx).
			WherePri(in.Id).Data(input_food.FoodOrderConfirmAgreeFields{
			BookingStatus: "CONFIRMED",
			BookingTime:   gtime.Now(),
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.FoodOrderLog.Ctx(ctx).OmitEmptyData().Insert(&entity.FoodOrderLog{
			OrderId:     int(in.Id),
			ActionWay:   "CONFIRMED",
			Remark:      "订单已确认",
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 更新餐厅预定量和预定金额
		if _, err = dao.FoodRestaurant.Ctx(ctx).Where(dao.FoodRestaurant.Columns().Id, models.RestaurantId).Update(g.MapStrAny{
			dao.FoodRestaurant.Columns().WaitConfirmOrderNum: gdb.Raw("wait_confirm_order_num-1"),
		}); err != nil {
			err = gerror.Wrap(err, "更新餐厅信息失败，请稍后重试！")
			return
		}
		return
	})

}

// ConfirmDisagree 确认失败，全额退款
func (s *sFoodOrder) ConfirmDisagree(ctx context.Context, in *input_food.FoodOrderConfirmDisagreeInp) (err error) {

	var models *entity.FoodOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "HAVE_PAID" {
		err = gerror.New("订单支付状态不正确")
		return
	}

	if models.BookingStatus != "WAIT_CONFIRM" {
		err = gerror.New("订单确认状态不正确")
		return
	}

	if models.RefundStatus != "WAIT" {
		err = gerror.New("订单已退款")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {

		// 改变订单确认状态
		if _, err = s.Model(ctx).TX(tx).
			WherePri(in.Id).Data(input_food.FoodOrderConfirmDisagreeFields{
			BookingStatus:       "CANCEL",
			ConfirmRefuseReason: in.BookingDisagreeReason,
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.FoodOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.FoodOrderLog{
			OrderId:     int(in.Id),
			ActionWay:   "DISCONFIRMED",
			Remark:      fmt.Sprintf("订单确认拒绝，原因：%s", in.BookingDisagreeReason),
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		// 确认失败、全额退款
		// 计算退款金额
		var (
			Transaction       []*entity.PmsTransaction
			TransactionRefund []*entity.PmsTransactionRefund
			RefundBalance     float64 // 可退款积分
			RefundFee         float64 // 第三方支付
		)
		if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().OrderSn, models.OrderSn).Scan(&Transaction); err != nil {
			return
		}
		if err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).Where(dao.PmsTransactionRefund.Columns().OrderSn, models.OrderSn).Scan(&TransactionRefund); err != nil {
			return
		}

		for _, v := range Transaction {
			// 可退款金额
			Refundable := v.Amount - v.RefundAmount
			if v.PayType == "BAL" {
				RefundBalance = RefundBalance + Refundable
			} else if v.PayType == "COUPON" {

			} else {
				RefundFee = RefundFee + Refundable
			}
		}
		// 退款金额
		RefundAmount := RefundBalance + RefundFee

		// 修改订单状态
		RefundStatus := "DONE"
		if models.OrderAmount > RefundAmount {
			RefundStatus = "PART"
		}
		if _, err = s.Model(ctx).TX(tx).
			WherePri(in.Id).Data(g.MapStrAny{
			dao.FoodOrder.Columns().RefundAmount:       RefundAmount,
			dao.FoodOrder.Columns().RefundBalAmount:    RefundBalance,
			dao.FoodOrder.Columns().RefundCouponAmount: 0,
			dao.FoodOrder.Columns().RefundStatus:       RefundStatus,
			dao.FoodOrder.Columns().RefundTime:         gtime.Now(),
			dao.FoodOrder.Columns().OrderStatus:        "CANCEL",
		}).Update(); err != nil {
			err = gerror.Wrap(err, "操作失败，请稍后重试！")
			return
		}

		// 更新餐厅预定量和预定金额
		if _, err = dao.FoodRestaurant.Ctx(ctx).TX(tx).Where(dao.FoodRestaurant.Columns().Id, models.RestaurantId).Update(g.MapStrAny{
			dao.FoodRestaurant.Columns().PayOrderNum:         gdb.Raw("pay_order_num-1"),
			dao.FoodRestaurant.Columns().PayOrderAmount:      gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			dao.FoodRestaurant.Columns().WaitConfirmOrderNum: gdb.Raw("wait_confirm_order_num-1"),
		}); err != nil {
			err = gerror.Wrap(err, "更新餐厅信息失败，请稍后重试！")
			return
		}

		// 更新套餐预定量和预定金额
		if _, err = dao.FoodGoods.Ctx(ctx).Where(dao.FoodGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
			dao.FoodGoods.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", models.GoodsNum)),
			dao.FoodGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
		}); err != nil {
			err = gerror.Wrap(err, "更新套餐信息失败，请稍后重试！")
			return
		}

		// 订单日志
		if _, err = dao.FoodOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.FoodOrderLog{
			OrderId:     int(in.Id),
			ActionWay:   "DISCONFIRMED",
			Remark:      "订单已退款",
			OperateType: "SYSTEM",
		}); err != nil {
			return err
		}

		// 全额退款
		err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
			OrderSn:      models.OrderSn,
			RefundAmount: RefundAmount,
		}, tx)
		if err != nil {
			err = gerror.Wrap(err, "退款操作失败，请稍后重试！")
			return
		}

		return
	})

}

// SettleOrderList 结算订单列表
func (s *sFoodOrder) SettleOrderList(ctx context.Context, in *input_food.SettleFoodOrderListInp) (list []*input_food.SettleFoodOrderListModel, totalCount int, err error) {
	mod := s.Model(ctx).WithAll()

	mod = mod.Fields(input_food.SettleFoodOrderListModel{})

	if !g.IsEmpty(in.SettlementOrderId) {
		mod = mod.Where(dao.FoodOrder.Columns().SettlementOrderId, in.SettlementOrderId)
	}

	if !g.IsEmpty(in.OrderSn) {
		mod = mod.WhereLike(dao.FoodOrder.Columns().OrderSn, "%"+in.OrderSn+"%")
	}

	if len(in.CreatedAt) == 2 {
		mod = mod.WhereBetween(dao.FoodOrder.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
	}

	mod = mod.Page(in.Page, in.PerPage)

	mod = mod.OrderDesc(dao.FoodOrder.Columns().Id)
	//mod = mod.Hook(hook2.PmsFindLanguageValueHook)

	if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
		err = gerror.Wrap(err, "获取结算订单列表失败，请稍后重试！")
		return
	}
	return
}

// CancelPay 取消订单
func (s *sFoodOrder) CancelPay(ctx context.Context, in *input_food.FoodOrderCancelPayInp) (err error) {

	var models *entity.FoodOrder
	if err = s.Model(ctx).Where("id", in.Id).Scan(&models); err != nil {
		err = gerror.Wrap(err, consts.ErrorORM)
		return
	}

	if models == nil {
		err = gerror.New("订单信息不存在或已被删除")
		return
	}

	if models.OrderStatus != "HAVE_PAID" {
		err = gerror.New("订单支付状态不正确")
		return
	}

	if models.VerifyStatus != "WAIT_VERIFY" {
		err = gerror.New("订单已核销")
		return
	}

	if models.AdminCancelNum > 0 {
		err = gerror.New("后台不可多次退款")
		return
	}

	return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {

		// 确认失败、全额退款
		// 计算退款金额
		var (
			Transaction       []*entity.PmsTransaction
			TransactionRefund []*entity.PmsTransactionRefund
			CancelFee         float64 // 退款手续费
			RefundBalance     float64 // 可退款积分
			RefundFee         float64 // 第三方支付
		)
		CancelFee = models.OrderAmount - models.CouponAmount - in.RefundMoney
		CancelFeeCalc := CancelFee
		if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().PayStatus, "DONE").Where(dao.PmsTransaction.Columns().OrderSn, models.OrderSn).Scan(&Transaction); err != nil {
			return
		}
		if err = dao.PmsTransactionRefund.Ctx(ctx).TX(tx).Where(dao.PmsTransactionRefund.Columns().OrderSn, models.OrderSn).Scan(&TransactionRefund); err != nil {
			return
		}

		for _, v := range Transaction {
			// 可退款金额
			Refundable := v.Amount - v.RefundAmount
			if v.PayType == "BAL" {
				if g.IsEmpty(CancelFeeCalc) {
					RefundBalance += Refundable
				} else if CancelFeeCalc > Refundable {
					RefundBalance += 0
					CancelFeeCalc = CancelFeeCalc - Refundable
				} else {
					RefundBalance += Refundable - CancelFeeCalc
					CancelFeeCalc = 0
				}
			} else if v.PayType == "COUPON" {

			} else {
				if g.IsEmpty(CancelFeeCalc) {
					RefundFee += Refundable
				} else if CancelFeeCalc > Refundable {
					RefundFee += 0
					CancelFeeCalc = CancelFeeCalc - Refundable
				} else {
					RefundFee += Refundable - CancelFeeCalc
					CancelFeeCalc = 0
				}
			}
		}
		// 退款金额
		RefundAmount := RefundBalance + RefundFee

		OrderTotalRefundAmount := RefundAmount + models.RefundAmount
		OrderTotalRefundBalance := RefundBalance + models.RefundBalAmount

		AdminOrderTotalRefundAmount := RefundAmount + models.AdminRefundAmount
		AdminOrderTotalRefundBalance := RefundBalance + models.AdminRefundBalAmount

		// 修改订单状态
		RefundStatus := "DONE"
		if models.OrderAmount > OrderTotalRefundAmount {
			RefundStatus = "PART"
		}
		if in.RefundType == 1 {
			// 仅退款
			if _, err = s.Model(ctx).TX(tx).
				WherePri(in.Id).Data(g.MapStrAny{
				//dao.FoodOrder.Columns().RefundFee:          CancelFee,
				dao.FoodOrder.Columns().RefundAmount:         OrderTotalRefundAmount,
				dao.FoodOrder.Columns().RefundBalAmount:      OrderTotalRefundBalance,
				dao.FoodOrder.Columns().AdminRefundAmount:    AdminOrderTotalRefundAmount,
				dao.FoodOrder.Columns().AdminRefundBalAmount: AdminOrderTotalRefundBalance,
				dao.FoodOrder.Columns().RefundCouponAmount:   0,
				dao.FoodOrder.Columns().RefundStatus:         RefundStatus,
				dao.FoodOrder.Columns().RefundTime:           gtime.Now(),
				dao.FoodOrder.Columns().AdminCancelReason:    in.AdminCancelReason,
			}).Update(); err != nil {
				err = gerror.Wrap(err, "操作失败，请稍后重试！")
				return
			}

			// 更新餐厅预定量和预定金额
			if _, err = dao.FoodRestaurant.Ctx(ctx).TX(tx).Where(dao.FoodRestaurant.Columns().Id, models.RestaurantId).Update(g.MapStrAny{
				dao.FoodRestaurant.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新餐厅信息失败，请稍后重试！")
				return
			}

			// 更新套餐预定量和预定金额
			if _, err = dao.FoodGoods.Ctx(ctx).Where(dao.FoodGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
				dao.FoodGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新套餐信息失败，请稍后重试！")
				return
			}
		} else {
			// 退款并取消
			if _, err = s.Model(ctx).TX(tx).
				WherePri(in.Id).Data(g.MapStrAny{
				//dao.FoodOrder.Columns().RefundFee:          CancelFee,
				dao.FoodOrder.Columns().RefundAmount:       OrderTotalRefundAmount,
				dao.FoodOrder.Columns().RefundBalAmount:    OrderTotalRefundBalance,
				dao.FoodOrder.Columns().RefundCouponAmount: 0,
				dao.FoodOrder.Columns().RefundStatus:       RefundStatus,
				dao.FoodOrder.Columns().RefundTime:         gtime.Now(),
				dao.FoodOrder.Columns().OrderStatus:        "CANCEL",
				dao.FoodOrder.Columns().AdminCancelReason:  in.AdminCancelReason,
			}).Update(); err != nil {
				err = gerror.Wrap(err, "操作失败，请稍后重试！")
				return
			}

			// 更新餐厅预定量和预定金额
			if _, err = dao.FoodRestaurant.Ctx(ctx).TX(tx).Where(dao.FoodRestaurant.Columns().Id, models.RestaurantId).Update(g.MapStrAny{
				dao.FoodRestaurant.Columns().PayOrderNum:    gdb.Raw("pay_order_num-1"),
				dao.FoodRestaurant.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新餐厅信息失败，请稍后重试！")
				return
			}

			if models.BookingStatus == "WAIT_CONFIRM" {
				if _, err = dao.FoodRestaurant.Ctx(ctx).TX(tx).Where(dao.FoodRestaurant.Columns().Id, models.RestaurantId).Update(g.MapStrAny{
					dao.FoodRestaurant.Columns().WaitConfirmOrderNum: gdb.Raw("wait_confirm_order_num-1"),
				}); err != nil {
					err = gerror.Wrap(err, "更新餐厅信息失败，请稍后重试！")
					return
				}
			}

			// 更新套餐预定量和预定金额
			if _, err = dao.FoodGoods.Ctx(ctx).Where(dao.FoodGoods.Columns().Id, models.GoodsId).Update(g.MapStrAny{
				dao.FoodGoods.Columns().PayOrderNum:    gdb.Raw(fmt.Sprintf("pay_order_num-%d", models.GoodsNum)),
				dao.FoodGoods.Columns().PayOrderAmount: gdb.Raw(fmt.Sprintf("pay_order_amount-%f", RefundAmount)),
			}); err != nil {
				err = gerror.Wrap(err, "更新套餐信息失败，请稍后重试！")
				return
			}
		}

		if _, err = dao.FoodOrder.Ctx(ctx).TX(tx).WherePri(in.Id).Update(g.MapStrAny{
			dao.FoodOrder.Columns().AdminCancelNum: gdb.Raw("admin_cancel_num+1"),
		}); err != nil {
			err = gerror.Wrap(err, "更新失败，请稍后重试！")
			return
		}

		if RefundAmount > 0 {
			// 退款
			err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
				OrderSn:      models.OrderSn,
				RefundAmount: RefundAmount,
			}, tx)
			if err != nil {
				err = gerror.Wrap(err, "退款操作失败，请稍后重试！")
				return
			}
		}

		// 订单日志
		if _, err = dao.FoodOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.FoodOrderLog{
			OrderId:     int(in.Id),
			ActionWay:   "ADMIN_REFUND",
			Remark:      fmt.Sprintf("后台退款，原因：%s", in.AdminCancelReason),
			OperateType: "ADMIN",
			OperateId:   int(contexts.GetUserId(ctx)),
		}); err != nil {
			return err
		}

		if in.RefundType == 2 {
			// 订单日志
			if _, err = dao.FoodOrderLog.Ctx(ctx).TX(tx).OmitEmptyData().Insert(&entity.FoodOrderLog{
				OrderId:     int(in.Id),
				ActionWay:   "CANCEL",
				Remark:      "后台订单取消",
				OperateType: "ADMIN",
				OperateId:   int(contexts.GetUserId(ctx)),
			}); err != nil {
				return err
			}
		}

		return
	})

}
